﻿// -----------------------------------------------------------------------
// <copyright file="ParseProject.cs" company="Microsoft">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Raop.Library.Aop
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Raop.Library.Tools;
    using System.IO;
    using Roslyn.Compilers.CSharp;
    using Roslyn.Compilers;
    using Raop.Library.Aop.PointCut;
    using System.Reflection.Emit;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public class ParseProject
    {
        public List<IBasePointCut> PointCuts { get; set; }

        public string ProjectName { get; private set; }

        public ParseProject(string projectName)
        {
            this.ProjectName = projectName;

            this.PointCuts = new List<IBasePointCut>();
            this.PointCuts.Add(new Raop.Library.Aop.PointCut.AttributPointCut());
            this.PointCuts.Add(new Raop.Library.Aop.PointCut.NamePointCut());
        }

        [Inject]
        public void Run()
        {
            var project = new ProjectReader(this.ProjectName);

            Compilation compil = CreateCompilation(project);

            var diagnostics = compil.GetDiagnostics().ToList();

            foreach (var d in diagnostics)
            {
                Console.WriteLine(d.Info);
            }

            if (diagnostics.Count > 0)
            {
                Console.WriteLine("Errors : " + diagnostics.Count);
                //Console.ReadLine();
                //return;
            }

            foreach (SyntaxTree sourceTree in compil.SyntaxTrees)
            {
                SemanticModel model = compil.GetSemanticModel(sourceTree);

                SyntaxNode node = sourceTree.Root;

                foreach (var pointCut in this.PointCuts)
                {
                    node = pointCut.MakeAop(compil, model, node);
                }

                FileInfo fi = new FileInfo(sourceTree.FileName);

                File.WriteAllText(sourceTree.FileName, node.GetFullText());
            }
        }

        private Compilation CreateCompilation(ProjectReader project)
        {
            var sources = new List<SyntaxTree>();

            foreach (var file in project.GetFiles())
            {
                string fileCode = File.ReadAllText(file);

                var syntax = SyntaxTree.ParseCompilationUnit(fileCode, file);
                sources.Add(syntax);
            }

            var assemblies = new List<MetadataReference>();

            var res = new AssemblyResolver(ReadOnlyArray<string>.CreateFrom(@"C:\Project\Raop\Raop\bin\Debug\"));
            foreach (var assemblyName in project.GetAssemblies())
            {
                AddAssembly(assemblies, res, assemblyName);
            }

            AddAssembly(assemblies, res, "mscorlib");

            foreach (var proj in project.GetDependencyProject())
            {
                List<string> assembliesAdded = new List<string>();

                foreach (var assemblyName in Directory.GetFiles(new FileInfo(proj).DirectoryName, "*.dll", SearchOption.AllDirectories))
                {
                    FileInfo fi = new FileInfo(assemblyName);

                    if (!assembliesAdded.Contains(fi.Name))
                    {
                        assemblies.Add(new AssemblyFileReference(assemblyName));
                    }

                    assembliesAdded.Add(fi.Name);
                }
            }

            return Compilation.Create("test", CompilationOptions.Default, sources, assemblies, null, null);
        }

        private static void AddAssembly(List<MetadataReference> assemblies, AssemblyResolver res, string assemblyName)
        {
            var path = res.ResolveAssemblyName(assemblyName);

            if (path != null)
            {
                var assembly = new AssemblyFileReference(path);
                assemblies.Add(assembly);
            }
        }
    }
}
